package ink.carnation.imtalk.controller.user;

import cn.hutool.core.util.HashUtil;
import ink.carnation.imtalk.annotation.IPLimit;
import ink.carnation.imtalk.annotation.Limiter;
import ink.carnation.imtalk.annotation.PassToken;
import ink.carnation.imtalk.model.IMResult;
import ink.carnation.imtalk.model.dto.UserLoginDTO;
import ink.carnation.imtalk.model.dto.UserRegisterDTO;
import ink.carnation.imtalk.model.dto.UserResetPasswordDTO;
import ink.carnation.imtalk.model.po.UserPo;
import ink.carnation.imtalk.model.vo.RegisterVO;
import ink.carnation.imtalk.service.EmailService;
import ink.carnation.imtalk.service.UserService;
import ink.carnation.imtalk.util.BindingResultUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

@CrossOrigin
@RestController
@RequestMapping("/users")
@Slf4j
@Api("用户服务相关")
public class UserController {
    @Autowired
    private UserService userService;
    @Autowired
    private EmailService emailService;

    @PostMapping("/register")
    @PassToken
    @Limiter(LimitNum = 5)
    @IPLimit(count = 5, time = 60)
    @ApiOperation("注册，传入email、nickname、password、validCode")
    public IMResult register(@Valid UserRegisterDTO userRegisterDTO, BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            return BindingResultUtil.getBindingResultMessage(bindingResult);
        }
        String email = userRegisterDTO.getEmail();
        String validCode = userRegisterDTO.getValidCode();
        UserPo userByEmail = userService.getUserByEmail(email);
        if (userByEmail != null) {
            return IMResult.failure("此email已注册!");
        }
        if (!(validCode != null && emailService.verification(email, validCode))) {
            return IMResult.failure("邮箱验证失败，请重试");
        }
        UserPo build = UserPo.builder()
                .nickname(userRegisterDTO.getNickname())
                .email(email)
                //Hutool RsHash加密
                .password(String.valueOf(HashUtil.rsHash(userRegisterDTO.getPassword())))
                .build();
        userService.insertUser(build);
        return IMResult.success(new RegisterVO(build.getId()));

    }

    @PostMapping("/login")
    @PassToken
    @Limiter(LimitNum = 5)
    @IPLimit(count = 5, time = 60)
    @ApiOperation("进行登录，传入userId、password")
    public IMResult login(@Valid UserLoginDTO userDTO, BindingResult bindingResult,
                          HttpServletResponse response) {
        if (bindingResult.hasErrors()) {
            return BindingResultUtil.getBindingResultMessage(bindingResult);
        }
        //先查布隆过滤器，如果不存在直接返回
        if (!userService.isBloomFilterExist(userDTO.getUserId())) {
            return IMResult.failure("用户不存在");
        }
        //再查缓存，如果存在，直接登录成功
        if (userService.isRedisTokenExist(response, userDTO.getUserId())) {
            return IMResult.success();
        }
        UserPo user = userService.getUserById(userDTO.getUserId());
        if (user == null) {
            return IMResult.failure("id错误");
        }
        if (userDTO.getPassword() == null) {
            return IMResult.failure("密码为空");
        }
        //Hutool rshash加密，判断加密后密文是否一致
        if (!String.valueOf(HashUtil.rsHash(userDTO.getPassword())).equals(user.getPassword())) {
            return IMResult.failure("密码错误");
        }
        userService.saveTokenToRedis(response, user.getId());
        return IMResult.success();
    }

    @GetMapping("/layout")
    @ApiOperation("注销")
    public IMResult layout(HttpServletRequest request) {
        userService.layout(request);
        return IMResult.success();
    }

    @PostMapping("/reset")
    @Limiter(LimitNum = 5)
    @IPLimit(count = 5, time = 60)
    @ApiOperation("重置密码，传入email和password和validCode，记得要邮箱验证")
    @PassToken
    public IMResult resetPassword(@Valid UserResetPasswordDTO userResetPasswordDTO, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return BindingResultUtil.getBindingResultMessage(bindingResult);
        }
        String email = userResetPasswordDTO.getEmail();
        String validCode = userResetPasswordDTO.getValidCode();
        if (!(validCode != null && emailService.verification(email, validCode))) {
            return IMResult.failure("验证码错误");
        }
        if (userService.resetPassword(email, userResetPasswordDTO.getPassword())) {
            return IMResult.success();
        } else {
            return IMResult.failure("邮箱错误");
        }
    }
}
